package com.ykt.common.utils;

import com.jfinal.plugin.activerecord.Model;
import com.ykt.common.constant.ParamNames;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ModelUtil {

    /**
     * 获取所有model类的ID列表，model必须包含“id”字段
     *
     * @param models 所有对象都集成了Model类，且都是以"id"为主键名
     * @return id列表
     */
    public static List<Integer> asIdList(List<? extends Model> models) {
        if (null == models || models.isEmpty()) {
            return Collections.emptyList();
        }

        List<Integer> ids = new ArrayList<>();
        for (Model model : models) {
            Integer id = model.getInt(ParamNames.id);
            if (id != null) {
                ids.add(id);
            }
        }

        return ids;
    }

    /**
     * 获取所有model类的ID对应其本身的Map，model必须包含“id”字段
     *
     * @param models 所有对象都集成了Model类，且都是以"id"为主键名
     * @return
     */
    public static Map<Integer, Object> asIdMap(List<? extends Model> models) {
        if (null == models || models.isEmpty()) {
            return Collections.emptyMap();
        }

        Map<Integer, Object> map = new HashMap<>();
        for (Model model : models) {
            Integer id = model.getInt(ParamNames.id);
            if (id != null) {
                map.put(id, model);
            }
        }

        return map;
    }

    private static char UNDERLINE = '_';
    private static char[] up = new char[26];
    private static char[] low = new char[26];

    static {
        char a = 'a', A = 'A';
        for (int i = 0; i < up.length; i++) {
            up[i] = (char) (A + i);
            low[i] = (char) (a + i);
        }
    }

    /**
     * 把Model类中的带下划线的字段名改为驼峰命名，注：model不能用于操作DB
     *
     * @param model 表模型类
     */
    public static void toHumpName(Model model) {
        toHumpName(model, null);
    }

    /**
     * 把Model类中的带下划线的字段名改为驼峰命名，注：model不能用于操作DB
     *
     * @param model     表模型类
     * @param rawFields 保持不变名的字段
     */
    public static void toHumpName(Model model, Set<String> rawFields) {
        toHumpName(model, null, rawFields);
    }

    /**
     * 把Model类中的带下划线的字段名改为驼峰命名，注：model不能用于操作DB
     *
     * @param model             表模型类
     * @param toUppercaseFields 需要把字段名改成大写
     * @param rawFields         保持不变名的字段
     */
    public static void toHumpName(Model model, Set<String> toUppercaseFields, Set<String> rawFields) {
        String names[] = model.getAttrNames();
        for (String name : names) {
            if (model.get(name) instanceof Model) {
                Model subModel = (Model) model.get(name);
                toHumpName(subModel, toUppercaseFields, rawFields);
            }

            if (toUppercaseFields != null) {
                if (toUppercaseFields.contains(name)) {

                    Object value = model.get(name);
                    model.remove(name);
                    model.put(name.toUpperCase(), value);
                }
            } else if (rawFields == null || !rawFields.contains(name)) {
                String humpName = toHumpName(name);
                Object value = model.get(name);
                model.remove(name);
                model.put(humpName, value);
            }
        }
    }


    private static String toHumpName(String name) {
        char[] names1 = name.toCharArray();
        for (int i = 0; i < names1.length; i++) {
            if (names1[i] == UNDERLINE) {
                if (i + 1 < names1.length) {
                    names1[i + 1] = Character.toUpperCase(names1[i + 1]);
                }
            }
        }

        int emptyPoint = 0;
        char[] names2 = new char[names1.length];
        for (int i = 0; i < names1.length; i++) {
            char ch = names1[i];

            while (ch == UNDERLINE) {
                i++;
                if (i == names1.length) {
                    i--;
                    break;
                }
                ch = names1[i];
            }

            names2[emptyPoint++] = names1[i];
        }

        char[] name3 = new char[emptyPoint];
        System.arraycopy(names2, 0, name3, 0, emptyPoint);

        return String.valueOf(name3);
    }

    public static void toUnderlineName(Model model) {
        toUnderlineName(model, null);
    }

    public static void toUnderlineName(Model model, Set<String> rawFields) {
        toUnderlineName(model, null, rawFields);
    }

    public static void toUnderlineName(Model model, Set<String> toUppercaseFields, Set<String> rawFields) {
        String names[] = model.getAttrNames();
        for (String name : names) {
            if (model.get(name) instanceof Model) {
                Model subModel = (Model) model.get(name);
                toUnderlineName(subModel, toUppercaseFields, rawFields);
            }

            if (toUppercaseFields != null) {
                if (toUppercaseFields.contains(name)) {

                    Object value = model.get(name);
                    model.remove(name);
                    model.put(name.toUpperCase(), value);
                }
            } else if (rawFields == null || !rawFields.contains(name)) {
                String humpName = toUnderlineName(name);
                Object value = model.get(name);
                model.remove(name);
                model.put(humpName, value);
            }
        }
    }

    private static String toUnderlineName(String name) {
        int uppercaseCount = 0;
        char[] names1 = name.toCharArray();
        for (char aNameArray : names1) {
            if (Character.isUpperCase(aNameArray)) {
                uppercaseCount++;
            }
        }

        char[] names2 = new char[uppercaseCount + names1.length];
        for (int i = 0, j = 0; i < names1.length; i++, j++) {

            int step = 0;
            while (Character.isUpperCase(names1[i + step])) {
                step++;
                if (i + step == names1.length) {
                    step--;
                    break;
                }
            }

            if (step == 0) {
                names2[j] = names1[i];
            } else {
                names2[j] = UNDERLINE;
                for (int s = 0; s < step; s++) {
                    names2[j + 1 + s] = Character.toLowerCase(names1[i + s]);
                }
                j += (step);
                i += (step - 1);
            }
        }

        int emptyPoint = 0;
        for (int i = 0; i < names2.length; i++) {
            if (names2[i] == '\u0000') {
                emptyPoint = i;
                break;
            }
        }

        if (emptyPoint == 0) {
            return String.valueOf(names2);
        }

        char names3[] = new char[emptyPoint];
        System.arraycopy(names2, 0, names3, 0, emptyPoint);
        return String.valueOf(names3);
    }

    /**
     * 获取model中指定字段的值，如果不存在返回0
     *
     * @param model 模型对象
     * @param field 字段名称
     * @return
     */
    public static double d(Model model, String field) {
        return d(model, field, 0);
    }

    public static double d(Model model, String field, double defaults) {
        if (model == null) {
            return defaults;
        }

        Object obj = model.get(field);
        if (obj == null) {
            return defaults;
        }

        if (obj instanceof Double) {
            return model.getDouble(field);
        } else if (obj instanceof BigDecimal) {
            return model.getBigDecimal(field).doubleValue();
        } else {
            return defaults;
        }
    }

    /**
     * 获取model中指定字段的值，如果不存在返回0
     *
     * @param model 模型对象
     * @param field 字段名称
     * @return
     */
    public static int i(Model model, String field) {
        return i(model, field, 0);
    }

    public static int i(Model model, String field, int defaults) {
        if(model == null){
            return defaults;
        }

        Object obj = model.get(field);
        if(obj == null){
            return defaults;
        }

        if(obj instanceof Integer){
            return (Integer)obj;
        } else {
            return defaults;
        }
    }

    /**
     * 获取model中指定字段的值，如果不存在返回0
     *
     * @param model 模型对象
     * @param field 字段名称
     * @return
     */
    public static long j(Model model, String field) {
        return j(model, field, 0);
    }

    public static long j(Model model, String field, long defaults) {
        if(model == null){
            return defaults;
        }

        Object obj = model.get(field);
        if(obj == null){
            return defaults;
        }

        if(obj instanceof Long){
            return (Long)obj;
        } else {
            return defaults;
        }
    }

    public static void main(String[] args) {
        Model mo = new Model() {
            @Override
            public Model use(String configName) {
                return super.use(configName);
            }
        };

        mo.set("aa_bb", 11);

        toHumpName(mo, null, null);
        System.out.println(mo);
    }
}
